package com.pp.admin.common.server.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.annotations.Element;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.pp.admin.common.client.beans.BaseUser;
import com.pp.admin.common.client.beans.LoginUserInfo;
import com.pp.admin.common.client.exceptions.DomainAuthException;
import com.pp.admin.common.server.PersistenceManagerFactory;

/**
 * The persistent class for the PP_USERS database table.
 */
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User extends Base implements Serializable {

	private static final long serialVersionUID = 1L;

	public static final byte STATUS_REQUESTED = 1;

	public static final byte STATUS_ACTIVE = 2;

	public static final byte STATUS_REJECTED = 3;

	public static final byte STATUS_DELETED = 4;

	@PrimaryKey
	@Persistent
	private Key id;

	@Persistent
	private String userID;

	@Persistent
	private String firstName;

	@Persistent
	private String lastName;

	@Persistent
	private String password;

	@Persistent
	private byte status;

	@Persistent
	private Key createdBy;

	@Persistent
	private Date createdByTime;

	@Persistent
	private Key lastModefiedBy;

	@Persistent
	private Date lastModefiedByTime;

	// uni-directional one-to-one association to Contact
	@Persistent(dependent = "true")
	private Contact contact;

	@Persistent
	private Set<Key> userDomainKeys = new HashSet<Key>();

	@Persistent(mappedBy = "owner")
	@Element(dependent = "true")
	private List<Domain> ownerOfDomains = new ArrayList<Domain>();

	public User() {

	}

	/**
	 * @return the id
	 */
	public Key getId() {

		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(Key id) {

		this.id = id;
	}

	/**
	 * @return the userID
	 */
	public String getUserID() {

		return userID;
	}

	/**
	 * @param userID
	 *            the userID to set
	 */
	public void setUserID(String userID) {

		this.userID = userID;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {

		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {

		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {

		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {

		this.lastName = lastName;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {

		return password;
	}

	/**
	 * @param password
	 *            the password to set
	 */
	public void setPassword(String password) {

		this.password = password;
	}

	/**
	 * @return the status
	 */
	public byte getStatus() {

		return status;
	}

	/**
	 * @param status
	 *            the status to set
	 */
	public void setStatus(byte status) {

		this.status = status;
	}

	/**
	 * @return the contact
	 */
	public Contact getContact() {

		return contact;
	}

	/**
	 * @param contact
	 *            the contact to set
	 */
	public void setContact(Contact contact) {

		this.contact = contact;
	}

	/**
	 * @return the userDomainKeys
	 */
	public Set<Key> getUserDomainKeys() {

		return userDomainKeys;
	}

	/**
	 * @param userDomainKeys
	 *            the userDomainKeys to set
	 */
	public void setUserDomainKeys(Set<Key> userDomainKeys) {

		this.userDomainKeys = userDomainKeys;
	}

	/**
	 * @return the ownerOfDomains
	 */
	public List<Domain> getOwnerOfDomains() {

		return ownerOfDomains;
	}

	/**
	 * @param ownerOfDomains
	 *            the ownerOfDomains to set
	 */
	public void setOwnerOfDomains(List<Domain> ownerOfDomains) {

		this.ownerOfDomains = ownerOfDomains;
	}

	/**
	 * @return the createdBy
	 */
	@Override
	public User getCreatedBy() {

		User user = null;
		PersistenceManager pm = PersistenceManagerFactory
				.getPersistenceManager();
		try {
			user = pm.getObjectById(User.class, this.createdBy);
		} finally {
			PersistenceManagerFactory.closePersistenceManager();
		}
		return user;
	}

	/**
	 * @param createdBy
	 *            the createdBy to set
	 */
	@Override
	public void setCreatedBy(Key createdBy) {

		this.createdBy = createdBy;
	}

	/**
	 * @return the createdByTime
	 */
	@Override
	public Date getCreatedByTime() {

		return createdByTime;
	}

	/**
	 * @param createdByTime
	 *            the createdByTime to set
	 */
	@Override
	public void setCreatedByTime(Date createdByTime) {

		this.createdByTime = createdByTime;
	}

	/**
	 * @return the lastModefiedBy
	 */
	@Override
	public User getLastModefiedBy() {

		User user = null;
		PersistenceManager pm = PersistenceManagerFactory
				.getPersistenceManager();
		try {
			user = pm.getObjectById(User.class, this.lastModefiedBy);
		} finally {
			PersistenceManagerFactory.closePersistenceManager();
		}
		return user;
	}

	/**
	 * @param lastModefiedBy
	 *            the lastModefiedBy to set
	 */
	@Override
	public void setLastModefiedBy(Key lastModefiedBy) {

		this.lastModefiedBy = lastModefiedBy;
	}

	/**
	 * @return the lastModefiedByTime
	 */
	@Override
	public Date getLastModefiedByTime() {

		return lastModefiedByTime;
	}

	/**
	 * @param lastModefiedByTime
	 *            the lastModefiedByTime to set
	 */
	@Override
	public void setLastModefiedByTime(Date lastModefiedByTime) {

		this.lastModefiedByTime = lastModefiedByTime;
	}

	public LoginUserInfo exportLoginUserInfo(String domain)
			throws DomainAuthException {

		LoginUserInfo user = new LoginUserInfo();
		PersistenceManager pm = PersistenceManagerFactory
				.getPersistenceManager();
		try {
			Key userDomainKey = UsersDomain.generateKey(domain, this.userID);
			UsersDomain usersDomain = pm.getObjectById(UsersDomain.class,
					userDomainKey);
			if (usersDomain == null) {
				throw new Exception();
			}
			user.setUserID(this.userID);
			user.setCurrentDomainID(domain);
			user.setSuperuser(usersDomain.isSuperUser());
		} catch (Exception ex) {
			throw new DomainAuthException();
		} finally {
			PersistenceManagerFactory.closePersistenceManager();
		}
		return user;
	}

	/**
	 * @return
	 */
	public BaseUser exportBaseUser() {

		BaseUser user = new BaseUser();

		return exportBaseUser(user);
	}

	public BaseUser exportBaseUser(BaseUser user) {
		user.setUserID(this.userID);
		user.setFirstName(this.firstName);
		user.setLastName(this.lastName);
		user.setStatus(this.status);
		user.setPassword(this.password);

		return user;
	}

	public com.pp.admin.common.client.beans.User exportUser() {
		com.pp.admin.common.client.beans.User user = new com.pp.admin.common.client.beans.User();
		exportBaseUser(user);
		user.setContact(this.contact.exportContact());
		return user;
	}

	/**
	 * @param user
	 * @return
	 */
	public User importUser(com.pp.admin.common.client.beans.User user) {

		/**
		 * TODO: Add server side validation before importing all the values.
		 */
		this.id = generateKey(user.getUserID());
		this.userID = user.getUserID();
		this.firstName = user.getFirstName();
		this.lastName = user.getLastName();
		this.password = user.getPassword();
		this.status = user.getStatus();
		if (user.getContact() != null) {
			Contact contact = new Contact().importContact(user.getContact());
			this.contact = contact;
		}
		return this;
	}

	public User update(com.pp.admin.common.client.beans.User user) {
		/**
		 * TODO: Add server side validation before importing all the values.
		 */
		if (this.firstName == null
				|| !this.firstName.equals(user.getFirstName())) {
			this.firstName = user.getFirstName();
		}
		if (this.lastName == null || !this.lastName.equals(user.getLastName())) {
			this.lastName = user.getLastName();
		}
		if (this.password == null || !this.password.equals(user.getPassword())) {
			this.password = user.getPassword();
		}
		if (this.status != user.getStatus()) {
			this.status = user.getStatus();
		}
		if(this.contact != null && user.getContact() != null) {
			this.contact.update( user.getContact() );
		}
		return this;
	}

	/**
	 * @param id
	 * @return
	 */
	public static Key generateKey(String id) {

		Key userKey = KeyFactory.createKey(User.class.getSimpleName(), id);
		return userKey;
	}

	public static User getUserByUserID(String userID) {

		User user = null;
		PersistenceManager pm = PersistenceManagerFactory
				.getPersistenceManager();
		try {
			Key userkey = generateKey(userID);
			user = pm.getObjectById(User.class, userkey);
		} finally {
			PersistenceManagerFactory.closePersistenceManager();
		}
		return user;
	}
}
